		TITLE	EXEPACK - Copyright (c) SLR Systems 1990

		INCLUDE MACROS

		PUBLIC	REAL_EXEPACK,REXE_INIT,MOVE_PACK_DATA,GET_EXEPACK_BYTES

		PUBLIC	GET_NEXT_BUFFER,INIT_INOUTBUF

DATA		SEGMENT WORD PUBLIC 'DATA'

	SOFT	EXTB	TEMP_RECORD,EXEPACK_TEMP,EXEPACK_BIGBUFFER,EOF_MSG

	SOFT	EXTW	EXEPACK_STACK

DATA		ENDS

DGROUP		GROUP	DATA

CODE		SEGMENT DWORD PUBLIC 'CODE'
		ASSUME	CS:CODE,SS:DGROUP

	SOFT	EXTN	DO_MSG,UPDATECRC32

COMMENT ~

	MUST HAVE AT LEAST THIS MANY DUPLICATES TO TRY IT...

FOR	REAL

;		ANY	INITIAL MID
;BYTES		  6	   6	  2
;WORDS		  4	   3	  2
;DWORDS 	  2	   2	  2

		ANY	INITIAL MID
BYTES            4        4      2
WORDS            3        2      2
TRIBYTES         2        2      2
DWORDS           2        2      2


~

REXE_INIT	PROC
		;
		;SET UP STUFF FOR USE LATER WHEN CALLED TO SUPPLY A BUFFER
		;
		CALL	INIT_INOUTBUF
		MOV	EXEPACK_TARG_PTR,OFF EXEPACK_BIGBUFFER+2
		MOV	OUTER_SP,SP
		LEA	SP,EXEPACK_STACK
		MOV	AX,OFF REAL_EXEPACK
		PUSH	AX
		PUSHM	DS,SI,ES,DI,DX,CX,BX,AX
		MOV	EXEPACK_SP,SP
		MOV	SP,OUTER_SP
		RET

REXE_INIT	ENDP

GET_EXEPACK_BYTES	PROC
		;
		;
		;
		PUSHM	ES,DI,DX,BX,AX
		MOV	OUTER_SP,SP
		MOV	SP,EXEPACK_SP
		POPM	AX,BX,CX,DX,DI,ES,SI,DS
		RET

GET_EXEPACK_BYTES	ENDP

REAL_EXEPACK:
		;
		;SI POINTS TO FIRST VALID POSITION
		;
		XOR	DX,DX

		ALIGN	4
MAIN_LOOP:
		LODSW
		CMP	[SI],AX 	;MATCH COULD BE BYTE OR WORD ITEM
		JZ	MAYBE_BW
;		CMP	1[SI],AX
;		JZ	MAYBE_TRI	;SEE IF TRI-BYTE MATCH
		CMP	2[SI],AX
		JZ	MAYBE_DWORD
MAYBE_RET:
		INC	DX		;COUNT BYTES THIS GROUP
		DEC	SI
MLC_1:
		CMP	BX,SI
		JA	MAIN_LOOP
MAIN_FILL:
		CALL	FLUSH_GET_NEXT_BUFFER	;COPY, THEN GET NEW
MAIN_LOOP_CHECK:
		CMP	EXEPACK_LIMIT,BX
		JNZ	MLC_1
		JMP	EXEPACK_FINISH

		ALIGN	4
MAYBE_DWORD:
		;
		;WELL, ONLY CHANCE IS 2 DWORDS
		;
		MOV	AX,[SI]
		CMP	4[SI],AX
		JZ	YES_DWORDS
		INC	DX
		DEC	SI
		CMP	BX,SI
		JA	MAIN_LOOP
		JMP	MAIN_FILL

		ALIGN	4
MAYBE_BW:
		;
		;GOT 2 WORDS MATCHING
		;
		CMP	AL,AH		;BYTES?
		JZ	YES_BYTES
		;
		;NEED TWO MORE MATCH FOR WORDS
		;
		CMP	2[SI],AX
		JZ	YES_WORDS
WORDS_3_ENUF?:
		OR	DX,DX
		JNZ	MAYBE_RET
		CMP	PACK_SO_FAR.LW,DX
MAYBE_RET1:
		JNZ	MAYBE_RET
YES_WORDS:
		DEC	SI
		DEC	SI
		CALL	STORE_BYTES_DX_1	;DX BYTES, 1 ITERATION
		MOV	AX,[SI]
		LEA	DI,[SI]
YES_WORD:
		;
		;WE AT LEAST HAVE 3 WORDS, SEE WHAT ELSE WE CAN COME UP WITH.
		;
		MOV	CX,BX
		SUB	CX,DI			;MAX WE CAN SCAN IN ONE SHOT
		SHR	CX,1
		MOV	DX,CX			;# WE SCANNED...
		CMP	AX,AX
		REPE	SCASW
		JZ	ANOTHER_WORD
		SUB	DX,CX			;# FOUND
		DEC	DX
		LEA	SI,-2[DI]
		CALL	STORE_WORDTYPE		;SPECIAL CASES HANDLED...
		XOR	DX,DX
		JMP	MAIN_LOOP_CHECK

ANOTHER_WORD:
		;
		;STILL CRUISING, GET ANOTHER BUFFER PLEASE
		;
		ADD	PACK_SO_FAR.LW,DX
		MOV	SI,DI
		CALL	GET_NEXT_BUFFER
		MOV	DI,SI
		JNC	YES_WORD
		XOR	DX,DX
		CALL	STORE_WORDTYPE
		XOR	DX,DX
		JMP	EXEPACK_FINISH

		ALIGN	4
YES_BYTES:
		;
		;GOT 6
		;
YES_BYTE:
		DEC	SI
		DEC	SI
		CALL	STORE_BYTES_DX_1	;STORE PREVIOUS COUNT
		MOV	AL,[SI]
		LEA	DI,[SI]
		;
		;WE AT LEAST HAVE 6 BYTES, SEE WHAT ELSE WE CAN COME UP WITH.
		;WE ARE SCANNING FOR BYTES...
		;
YB_1:
		MOV	CX,BX
		SUB	CX,DI			;MAX WE CAN SCAN IN ONE SHOT
		MOV	DX,CX			;# WE SCANNED...
		REPE	SCASB
		JZ	ANOTHER_BYTE
		SUB	DX,CX			;# FOUND
		DEC	DX
		LEA	SI,-1[DI]
		CALL	STORE_BYTETYPE		;SPECIAL CASES HANDLED...
		XOR	DX,DX
		JMP	MAIN_LOOP_CHECK

YES_DWORDS:
		DEC	SI
		DEC	SI
		CALL	STORE_BYTES_DX_1
		MOV	AX,[SI]
		MOV	DI,2[SI]

		;WE ARE SCANNING FOR DWORDS...
YD_1:
		MOV	CX,BX
		SUB	CX,SI			;MAX WE CAN SCAN IN ONE SHOT
		SHRI	CX,2
		MOV	DX,CX			;# WE SCANNED...
		JCXZ	ANOTHER_DWORD
YD_2:
		CMP	[SI],AX
		JNZ	YD_DONE
		CMP	2[SI],DI
		JNZ	YD_DONE
		ADD	SI,4
		LOOP	YD_2
		JMP	ANOTHER_DWORD

YD_DONE:
		SUB	DX,CX			;# FOUND
		CALL	STORE_DWORDTYPE 	;SPECIAL CASES HANDLED...
		XOR	DX,DX
		JMP	MAIN_LOOP_CHECK

ANOTHER_BYTE:
		;
		;STILL CRUISING, GET ANOTHER BUFFER PLEASE
		;
		;BX DUPLICATE BYTES LIKE AL HAVE BEEN STORED
		;
		ADD	PACK_SO_FAR.LW,DX
		ADC	PACK_SO_FAR.HW,0
		MOV	SI,DI
		CALL	GET_NEXT_BUFFER
		MOV	DI,SI
		JNC	YB_1
		XOR	DX,DX
		CALL	STORE_BYTETYPE
		XOR	DX,DX
		JMP	EXEPACK_FINISH

ANOTHER_DWORD:
		ADD	PACK_SO_FAR.LW,DX
		CALL	GET_NEXT_BUFFER
		JNC	YD_1
		XOR	DX,DX
		CALL	STORE_DWORDTYPE
		XOR	DX,DX
		JMP	EXEPACK_FINISH

EXEPACK_FINISH:
		;
		;FLUSH PARTIAL BLOCK
		;
;		CALL	STORE_BYTES_DX_1
		;
		;FLUSH DANGLING PIECE
		;
		MOV	DX,EXEPACK_LIMIT
		SUB	DX,SI
		ADD	SI,DX
		CALL	STORE_BYTES_DX_1
		;
		;NOW SIGNAL END OF EXEPACK DATA
		;
		LEA	SI,EXEPACK_BIGBUFFER
		MOV	WPTR [SI],-1
		MOV	CX,2
		CALL	MOVE_PACK_DATA

EXP_FIN_1:
		XOR	CX,CX
		MOV	SLR_BYTES_LEFT.LW,CX
		MOV	SLR_BYTES_LEFT.HW,CX
		CALL	MOVE_PACK_DATA
		JMP	EXP_FIN_1


;		JMP	REAL_RELOC_FLUSH

		ALIGN	4
MOVE_DX_TARG	PROC
		;
		;MOVE DX BYTES FROM DS:SI-DX TO TARG_ADDR, UPDATE TARG_ADDR
		;AND PACK_SO_FAR
		;
		ADD	PACK_SO_FAR.LW,DX
;		ADC	PACK_SO_FAR.HW,0
;		JNZ	MOVE_DX_TARG_A
;		CMP	PACK_SO_FAR.LW,0
		JZ	9$
MOVE_DX_TARG_A:
		PUSHM	SI,BX
		MOV	CX,DX
		SUB	SI,CX
		MOV	DI,EXEPACK_TARG_PTR
		ADD	EXEPACK_TARG_PTR,CX
;		CALL	MOVE_PACK_DATA
		OPTI_MOVSB
		MOV	EXEPACK_TARG_PTR,DI
		POPM	BX,SI
		XOR	DX,DX
9$:
		RET

MOVE_DX_TARG	ENDP

FGNB_FULL:
		;
		;USE STORE_BYTES_DX_1 TO GET RID OF 32K OF STUFF
		;
		SUB	AX,16K		;# OF BYTES > 16K
;		NEG	AX
		SUB	SI,AX
		SUB	DX,AX
		PUSH	AX
		CALL	STORE_BYTES_DX_1
		POP	DX
		ADD	SI,DX

FLUSH_GET_NEXT_BUFFER:
		;
		;MAKE SURE NOT >32K-1...
		;
		MOV	AX,PACK_SO_FAR.LW
		ADD	AX,DX
		CMP	AX,4000H
		JAE	FGNB_FULL
		CALL	MOVE_DX_TARG
		;
GET_NEXT_BUFFER PROC
		;
		;GET TEMP_RECORD FILLED WITH DATA PLEASE
		;
		PUSHM	DI,AX
		LEA	DI,TEMP_RECORD		;MOVE TAIL TO BOTTOM
		LEA	SI,-4[SI]		;FOR DWORD CHECKING...
		MOV	CX,EXEPACK_LIMIT
		SUB	CX,SI
		REP	MOVSB
5$:
		;
		;NEED TO READ SOME DATA FROM FILE
		;
		;MOVE SMALLER OF TEMP_RECORD_SIZE AND INFILE_BYTES_LEFT
		;
		MOV	CX,TEMP_RECORD_SIZE
		CMP	INFILE_BYTES_LEFT.HW,0
		JNZ	51$
		MOV	AX,INFILE_BYTES_LEFT.LW
		CMP	AX,CX
		JA	51$
		MOV	CX,AX
51$:
		;
		;CX IS # OF BYTES TO READ
		;
		JCXZ	7$
		MOV	DX,DI
		MOV	BX,ASCIZ0_HANDLE
		MOV	AH,3FH
		DO_INT21
		CMP	AX,CX
		JNZ	9$
		SUB	INFILE_BYTES_LEFT.LW,AX
		SBB	INFILE_BYTES_LEFT.HW,0
		ADD	DI,AX
		;
		;ADD IN CRC32
		;
		MOV	SI,DX
		MOV	AX,CRC32_SO_FAR.LW
		MOV	DX,CRC32_SO_FAR.HW
		CALL	UPDATECRC32
		MOV	CRC32_SO_FAR.LW,AX
		MOV	CRC32_SO_FAR.HW,DX
3$:
		LEA	SI,TEMP_RECORD+4
		MOV	BX,DI
		SUB	BX,EXEPACK_TAIL_LIMIT
		CMP	BX,SI
		JB	5$
		POP	AX
		MOV	EXEPACK_LIMIT,DI
		POP	DI
		XOR	DX,DX
		RET

7$:
		BITT	EXEPACK_FLUSHING
		JNZ	8$
		;
		;NO BYTES LEFT, MOVE PARTIAL BACK TO EXEPACK_TEMP
		;
		MOV	CX,DI
		LEA	SI,TEMP_RECORD
		LEA	DI,EXEPACK_TEMP
		SUB	CX,SI
		MOV	EXEPACK_DANGLE_LEN,CX
		REP	MOVSB
		XCHG	SI,DI
		LEA	SI,TEMP_RECORD+4
		LEA	BX,[DI]
		POP	AX
		MOV	EXEPACK_LIMIT,DI
		POP	DI
		MOV	EXEPACK_DANGLE_LEN,4
		SETT	EXEPACK_FLUSHING	;CLEARS CARRY TOO
		XOR	DX,DX
		RET

8$:
		LEA	SI,TEMP_RECORD+4
		LEA	BX,[DI]
		POP	AX
		MOV	EXEPACK_LIMIT,DI
		POP	DI
		XOR	DX,DX
		STC
		RET

9$:
		LEA	SI,EOF_MSG
		JMP	DO_MSG

GET_NEXT_BUFFER ENDP

INIT_INOUTBUF	PROC
		;
		;INITIALIZE STUFF
		;
		LEA	SI,EXEPACK_TEMP
		MOV	AX,EXEPACK_DANGLE_LEN
		ADD	AX,SI
		MOV	EXEPACK_LIMIT,AX

		XOR	AX,AX
		LEA	SI,EXEPACK_TEMP+4
		JMP	GET_NEXT_BUFFER

INIT_INOUTBUF	ENDP

STORE_DWORDTYPE PROC
		;
		;DX MORE DWORDS FOUND, FLUSH THIS ALL
		;
		ADD	PACK_SO_FAR.LW,DX
		JZ	9$		;NONE REALLY, SKIP IT
		CMP	PACK_SO_FAR.LW,0FFFH
		JA	1$
0$:
;		ADD	PACK_SO_FAR.LW,0E000H-1
FLUSH_DWORDTYPE:
		MOV	DX,4
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR
		PUSH	SI
		MOV	AX,PACK_SO_FAR.LW
		DEC	AX
		CMP	AX,16
		JAE	8$
		ADD	AL,112
		JMP	SBDX_1

8$:
		ADD	AX,0F000H
		XCHG	AL,AH
		JMP	SBDX_1

1$:
		MOV	CX,PACK_SO_FAR.LW
2$:
		PUSH	CX
		MOV	PACK_SO_FAR.LW,0FFFH
		CALL	FLUSH_DWORDTYPE
		POP	CX
		SUB	CX,0FFFH
		JZ	9$
		CMP	CX,0FFFH
		JA	2$
		MOV	PACK_SO_FAR.LW,CX
		JMP	0$

9$:
		RET

STORE_DWORDTYPE ENDP

STORE_WORDTYPE	PROC
		;
		;DX MORE WORDS FOUND, FLUSH THIS ALL
		;
		ADD	PACK_SO_FAR.LW,DX		;MUST USE 32-BIT BECAUSE OF EXEPACK_ZEROS
		ADC	PACK_SO_FAR.HW,0		;GETTING CHANGED TO WORDS...

		MOV	AX,PACK_SO_FAR.LW
		OR	AX,PACK_SO_FAR.HW
		JZ	9$
0$:
		CMP	PACK_SO_FAR.HW,0
		JNZ	1$
		CMP	PACK_SO_FAR.LW,2000H
		JA	1$
;		ADD	PACK_SO_FAR.LW,0A000H-1
FLUSH_WORDTYPE:
		MOV	DX,2
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR
		PUSH	SI
		MOV	AX,PACK_SO_FAR.LW
		DEC	AX
		CMP	AX,16
		JB	8$
		ADD	AX,0D000H
		XCHG	AH,AL
		JMP	SBDX_1		;STORE PACK_SO_FAR AT REPT LOCATION

8$:
		ADD	AL,96
		JMP	SBDX_1

1$:
		PUSHM	PACK_SO_FAR.LW,PACK_SO_FAR.HW
		MOV	PACK_SO_FAR.LW,02000H
		CALL	FLUSH_WORDTYPE
		POPM	PACK_SO_FAR.HW,PACK_SO_FAR.LW
		SUB	PACK_SO_FAR.LW,2000H
		SBB	PACK_SO_FAR.HW,0
		JMP	0$

9$:
		RET

STORE_WORDTYPE	ENDP

STORE_BYTETYPE	PROC
		;
		;DX MORE BYTES FOUND, FLUSH THIS ALL
		;
		ADD	PACK_SO_FAR.LW,DX
		ADC	PACK_SO_FAR.HW,0
		;
		;OK, IF BYTES GENERATED, PROVE IT
		;
		MOV	AX,PACK_SO_FAR.LW
		OR	AX,PACK_SO_FAR.HW
		JZ	9$
0$:
		CMP	PACK_SO_FAR.HW,0
		JNZ	CHANGE_TO_WORD
		CMP	PACK_SO_FAR.LW,1000H
		JA	CHANGE_TO_WORD
;		ADD	PACK_SO_FAR.LW,4000H-1
FLUSH_BYTETYPE:
		MOV	DX,1
		CALL	MOVE_DX_TARG_A	;MV DX BYTES FM DS:SI-DX TO TARG_ADDR
STORE_PACK:
		PUSH	SI
		MOV	AX,PACK_SO_FAR.LW
		DEC	AX
		CMP	AX,32
		JB	8$
		ADD	AX,0C000H
		XCHG	AH,AL
		JMP	SBDX_1

8$:
		ADD	AL,64
		JMP	SBDX_1

9$:
		RET

CHANGE_TO_WORD:
		TEST	BPTR (PACK_SO_FAR.LW),1
		JNZ	1$
		SHR	PACK_SO_FAR.HW,1
		RCR	PACK_SO_FAR.LW,1
		MOV	AL,-1[SI]
		MOV	-2[SI],AL
		XOR	DX,DX
		JMP	STORE_WORDTYPE

1$:
		;
		;ODD # OF BYTES, GENERATE 0FFFH BYTES FIRST, THEN TRY AGAIN
		;
		PUSHM	PACK_SO_FAR.LW,PACK_SO_FAR.HW
		MOV	PACK_SO_FAR.LW,0FFEH
		CALL	FLUSH_BYTETYPE
		POPM	PACK_SO_FAR.HW,PACK_SO_FAR.LW
		SUB	PACK_SO_FAR.LW,0FFFH
		SBB	PACK_SO_FAR.HW,0
		JMP	0$

STORE_BYTETYPE	ENDP

;		ALIGN	4
STORE_BYTES_DX_1	PROC
		;
		;
		;
		CMP	DX,7
		JA	5$
		CMP	PACK_SO_FAR.LW,0
		JNZ	5$
		CMP	DX,2
		JB	5$
		;
		;MAYBE WE CAN SQUEEZE JUST A LITTLE BIT MORE...
		;
		;FIRST, TRY FOR DX MATCHING BYTES...
		;
		SUB	SI,DX
		MOV	CX,DX
		MOV	DI,SI
		MOV	AL,[SI]
		REPE	SCASB
		JZ	1$		;YES!
		MOV	DI,SI
		MOV	CX,DX
		SHR	CX,1
		JC	4$		;CANNOT!
		MOV	AX,[SI]
		REPE	SCASW
		JNZ	4$		;NOPE!
		;
		;WORDS
		;
		ADD	SI,DX
		SHR	DX,1
		JMP	STORE_WORDTYPE

1$:
		;
		;BYTES
		;
		ADD	SI,DX
		JMP	STORE_BYTETYPE

4$:
		ADD	SI,DX
5$:
		;
		;HANDLE CROSSING 16K BOUNDARY...
		;
		MOV	AX,PACK_SO_FAR.LW
		ADD	AX,DX
		CMP	AX,16K
		JBE	6$
		SUB	AX,16K
		PUSH	AX		;AMOUNT TO MOVE NEXT TIME
		SUB	SI,AX
		SUB	DX,AX
		CALL	6$
		POP	DX
		ADD	SI,DX

6$:
		CALL	MOVE_DX_TARG
		MOV	AX,PACK_SO_FAR.LW
		OR	AX,PACK_SO_FAR.HW
		JZ	9$
		PUSH	SI
		MOV	AX,PACK_SO_FAR.LW
		DEC	AX
		CMP	AX,64
		JB	SBDX_1
		XCHG	AH,AL
		OR	AL,80H
SBDX_1:
		;
		;HAS FIRST REPT_WORD BEEN STORED IN UNPACKER YET?
		;
		OR	AL,AL
		LEA	SI,EXEPACK_BIGBUFFER+1
		JS	7$
		MOV	[SI],AL
8$:
		MOV	CX,EXEPACK_TARG_PTR
		SUB	CX,SI
		CALL	MOVE_PACK_DATA
		POP	SI
		MOV	EXEPACK_TARG_PTR,OFF EXEPACK_BIGBUFFER+2
		XOR	AX,AX
		MOV	PACK_SO_FAR.LW,AX
		MOV	PACK_SO_FAR.HW,AX
9$:
		RET

7$:
		DEC	SI
		MOV	[SI],AX
		JMP	8$

STORE_BYTES_DX_1	ENDP

MOVE_PACK_DATA	PROC
		;
		;SEND THIS DATA ON TO COMPRESSER
		;
		;DS:SI IS SOURCE, CX IS BYTE_COUNT
		;
		PUSHM	DS,SI,ES,DI,DX,CX,BX,AX
		MOV	EXEPACK_SP,SP
		MOV	SP,OUTER_SP
		POPM	AX,BX,DX,DI,ES
		RET

MOVE_PACK_DATA	ENDP

CODE		ENDS

		END
